package com.lzy.oss;

import com.aliyun.oss.OSS;
import com.aliyun.oss.model.*;
import com.lzy.properties.AliyunOSSProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import sun.misc.BASE64Decoder;

import java.io.*;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.*;

@Slf4j
public class AliyunOSSService {


    private OSS oss;

    private AliyunOSSProperties properties;

    public AliyunOSSService(AliyunOSSProperties properties, OSS oss) {
        this.properties = properties;
        this.oss = oss;
    }

    /**
     * 创建空间
     *
     * @param bucketName 存储空间
     * @return String
     */
    public String createBucketName(String bucketName) {
        //存储空间
        if (!oss.doesBucketExist(bucketName)) {
            //创建存储空间
            Bucket bucket = oss.createBucket(bucketName);
            return bucket.getName();
        }
        return bucketName;
    }

    /**
     * 创建文件夹
     *
     * @param bucketName 存储空间
     * @param folder
     * @return 文件夹名
     */
    public String createFolder(String bucketName, String folder) {
        //文件夹名
        //判断文件夹是否存在，不存在则创建
        if (!oss.doesObjectExist(bucketName, folder)) {
            //创建文件夹
            oss.putObject(bucketName, folder, new ByteArrayInputStream(new byte[0]));
            //得到文件夹名
            OSSObject object = oss.getObject(bucketName, folder);
            return object.getKey();
        }
        return folder;
    }

    /**
     * 上传文件至OSS
     *
     * @param file       上传文件（文件全路径）
     * @param bucketName 存储空间
     * @param folder     模拟文件夹名
     * @return String 返回的唯一MD5数字签名
     */
    public String uploadObject2OSS(File file, String bucketName, String folder, int length) {
        //以输入流的形式上传文件
        InputStream is = null;
        try {
            is = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            log.error("文件读取失败", e);
            throw new RuntimeException("文件读取失败", e);
        }
        String fileName = file.getName();
        return putObject(bucketName, folder + fileName, is);

    }

    /**
     * 通过文件名判断并获取OSS服务文件上传时文件的contentType
     *
     * @param fileName 文件名
     * @return 文件的contentType
     */
    public String getContentType(String fileName) {
        //文件的后缀名
        String fileExtension = fileName.substring(fileName.lastIndexOf("."));
        fileExtension = fileExtension.trim();
        if (".bmp".equalsIgnoreCase(fileExtension)) {
            return "image/bmp";
        }
        if (".gif".equalsIgnoreCase(fileExtension)) {
            return "image/gif";
        }
        if (".jpeg".equalsIgnoreCase(fileExtension) || ".jpg".equalsIgnoreCase(fileExtension) || ".png".equalsIgnoreCase(fileExtension)) {
            return "image/jpeg";
        }
        if (".html".equalsIgnoreCase(fileExtension)) {
            return "text/html";
        }
        if (".txt".equalsIgnoreCase(fileExtension)) {
            return "text/plain";
        }
        if (".vsd".equalsIgnoreCase(fileExtension)) {
            return "application/vnd.visio";
        }
        if (".ppt".equalsIgnoreCase(fileExtension) || ".pptx".equalsIgnoreCase(fileExtension)) {
            return "application/vnd.ms-powerpoint";
        }
        if (".doc".equalsIgnoreCase(fileExtension) || ".docx".equalsIgnoreCase(fileExtension)) {
            return "application/msword";
        }
        if (".xml".equalsIgnoreCase(fileExtension)) {
            return "text/xml";
        }
        if (".apk".equalsIgnoreCase(fileExtension)) {
            return "application/vnd.android.package-archive";
        }
        if (".mp4".equalsIgnoreCase(fileExtension)) {
            return "video/mp4";
        }
        if (".x-flv".equalsIgnoreCase(fileExtension)) {
            return "video/x-flv";
        }
        if (".avi".equalsIgnoreCase(fileExtension)) {
            return "video/avi";
        }
        if (".rmvb".equalsIgnoreCase(fileExtension) || ".rm".equalsIgnoreCase(fileExtension)) {
            return "application/octet-stream";
        }
        if (".wmv".equalsIgnoreCase(fileExtension)) {
            return "video/x-ms-wmv";
        }
        if (".mov".equalsIgnoreCase(fileExtension)) {
            return "video/quicktime";
        }
        if (".3gp".equalsIgnoreCase(fileExtension)) {
            return "video/3gpp";
        }
        //默认返回类型
        return "image/jpeg";
    }

    /**
     * 获得url链接
     *
     * @param key        key
     * @param backetName backetName
     * @return String
     */
    public String getUrl(String key, String backetName) {
        // 设置URL有效期
        Date expiration = new Date(System.currentTimeMillis() + 3600L * 1000 * 24 * 365 * 100);
        // 生成URL
        URL url = oss.generatePresignedUrl(backetName, key, expiration);
        if (url != null) {
            return url.toString();
        }
        return null;
    }

    /**
     * 获得返回路径
     *
     * @param fileUrl    fileUrl
     * @param backetName backetName
     * @param folder     folder
     * @return String
     */
    public String getImgUrl(String fileUrl, String backetName, String folder) {
        if (!StringUtils.isEmpty(fileUrl)) {
            String[] split = fileUrl.split("/");
            return getUrl(folder + split[split.length - 1], backetName);
        }
        return null;
    }

    /**
     * 文件上传
     * 返回oss网络路径,可直接浏览器访问或下载
     *
     * @param folder folder
     * @param file   file
     * @return String
     */
    public String aLiYunOssUpload(File file, String folder, int length) {
        String md5key = uploadObject2OSS(file, properties.getBucketName(), properties.getFilehostType(), length);
        log.info("md5key:" + md5key);
        return "https://" + properties.getBucketName() + "." + properties.getEndPoint() + "/" + properties.getFilehostType() + file.getName();
    }

    /**
     * 上传base64文件
     *
     * @param imageBase64Str 图片base64代码
     * @param fileType       文件类型文件夹  （image,excel...)
     * @return
     */
    public String uploadBase64(String imageBase64Str, String fileType) {
        //初始化OSSClient
        String bucket = properties.getBucketName();
        String packageName = properties.getFilehostType() + fileType;
        InputStream inputStream1;
        String[] shartimg = new String[2];
        if (!imageBase64Str.isEmpty()) { //base64所在字段
            shartimg = imageBase64Str.split(",");
            int index = shartimg[0].indexOf("/");
            int endindex = shartimg[0].indexOf(";");
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
            String date = sdf.format(new Date());
            String endName = shartimg[0].substring(index + 1, endindex);//获取文件后缀
            String newFileName = date + "." + endName;// 新文件名
            try {
                byte[] bytes = new BASE64Decoder().decodeBuffer(shartimg[1]);  //将字符串转换为byte数组
                inputStream1 = new ByteArrayInputStream(bytes);
                ObjectMetadata metadata = new ObjectMetadata();
                metadata.setContentLength(inputStream1.available());
                oss.putObject(bucket, packageName + "/" + newFileName, inputStream1, metadata);
            } catch (IOException e) {
                log.error("图片写入失败,", e);
            }
            return properties.getShowImageHost() + packageName + "/" + newFileName;
        }
        return "";
    }


    public String uploadBase64(String imageBase64Str, String fileType, String endName, String newFileName) {
        String bucket = properties.getBucketName();
        String packageName = properties.getFilehostType() + fileType;
        InputStream inputStream1;
        if (!imageBase64Str.isEmpty()) {
            if (newFileName == null || newFileName.length() == 0) {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
                newFileName = sdf.format(new Date());
            }
            newFileName += "." + endName;// 新文件名
            try {
                byte[] bytes = new BASE64Decoder().decodeBuffer(imageBase64Str);
                inputStream1 = new ByteArrayInputStream(bytes);
                ObjectMetadata metadata = new ObjectMetadata();
                metadata.setContentLength(inputStream1.available());
                oss.putObject(bucket, packageName + "/" + newFileName, inputStream1, metadata);
            } catch (IOException e) {
                log.error("图片上传失败", e);
            }
            return properties.getShowImageHost() + packageName + "/" + newFileName;
        }
        return "";
    }


    /**
     * 图片地址封装成Map对象
     *
     * @param imageBase64Str
     * @return
     */
    public Map<String, Object> getUploadPathObj(String imageBase64Str) {
        Map<String, Object> result = new HashMap<String, Object>();
        result.put("filePath", uploadBase64(imageBase64Str, "image"));
        return result;
    }


    /**
     * 文件删除(批量)
     *
     * @param keys keys
     * @return Map
     */
    public Map<String, Object> aLiYunOssDelete(List<String> keys) {

        //初始化OSSClient
        try {
            Map<String, Object> result = new HashMap<String, Object>();
            DeleteObjectsResult deleteObjectsResult = oss.deleteObjects(new DeleteObjectsRequest(properties.getBucketName()).withKeys(keys));
            //返回的成功删除Object的结果
            List<String> deletedObjects = deleteObjectsResult.getDeletedObjects();
            int count = 0;
            for (String string : deletedObjects) {
                count = count + 1;
                result.put("item" + count, "第" + count + "张:" + string);
            }
            if (keys.size() == deletedObjects.size()) {
                result.put("status", 0);
            } else {
                result.put("status", 1);
            }
            result.put("successCount", deletedObjects.size());
            return result;
        } catch (Exception e) {
            log.error("图片删除失败", e);
            Map<String, Object> result = new HashMap<String, Object>();
            result.put("status", 1);
            result.put("msg", "删除--阿里云OSS服务器异常.");
            return result;
        }
    }

    /**
     * oss下载文件到本地
     *
     * @param bucketName oss桶
     * @param key        oss文件key
     * @param filePath   本地保存文件路径
     */
    public void down(String bucketName, String key, String filePath) {
        // 下载OSS文件到本地文件。如果指定的本地文件存在会覆盖，不存在则新建。
        oss.getObject(new GetObjectRequest(bucketName, key), new File(filePath));
    }

    /**
     * oss下载文件到本地
     *
     * @param bucketName oss桶
     * @param key        oss文件key
     */
    public InputStream down(String bucketName, String key) {
        OSSObject ossObject = oss.getObject(new GetObjectRequest(bucketName, key));
        return ossObject.getObjectContent();
    }


    /**
     * 将inputstream  上传阿里云
     *
     * @param bucket      阿里云bucket  本项目是 hxxf-image
     * @param filePath    完整路径 /test/20190831162511.jpg
     * @param inputStream inputStream流
     * @return 返回地址 ：https://hxxf-image.oss-cn-shenzhen.aliyuncs.com/test/20190831162511.jpg
     */
    public String putObject(String bucket, String filePath, InputStream inputStream) {
        ObjectMetadata metadata = new ObjectMetadata();
        try {
            metadata.setContentLength(inputStream.available());
            oss.putObject(bucket, filePath, inputStream, metadata);
            return properties.getShowImageHost() + "/" + filePath;
        } catch (IOException e) {
            log.error("文件上传失败:", e);
            throw new RuntimeException("图片上传失败", e);
        }
    }

    /**
     * 将inputstream  上传阿里云
     *
     * @param filePath    oss存储目录 prod/miniprogram/form
     * @param inputStream inputStream流
     * @return 返回地址 ：https://hxxf-image.oss-cn-shenzhen.aliyuncs.com/test/20190831162511.jpg
     */
    public String putObject(String filePath, InputStream inputStream, String suffix) {
        ObjectMetadata metadata = new ObjectMetadata();
        try {
            String uuid = UUID.randomUUID().toString().replaceAll("-", "");
            filePath = filePath + uuid + "." + suffix;
            metadata.setContentLength(inputStream.available());
            oss.putObject(properties.getBucketName(), filePath, inputStream, metadata);
            return properties.getShowImageHost() + "/" + filePath;
        } catch (IOException e) {
            log.error("文件上传失败:", e);
            throw new RuntimeException("图片上传失败", e);
        }
    }

}
